package it.tukano.beanstore;

import it.tukano.collections.ListExt;
import it.tukano.fun.Function1;
import it.tukano.fun.OptionalValue;
import it.tukano.io.FileExt.InputStreamCall;
import it.tukano.io.FileExt.OutputStreamCall;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;

/**
 * A persistence layer for java beans objects
 * @author pgi
 */
public interface BeanStore {
    
    /**
     * Delete the bean with the given uid
     * @param uid the uid of the bean to delete
     */
    void delete(String uid) throws BeanStoreException;

    /**
     * Save or update a bean in the store
     * @param uid the uid of the bean to store or update
     * @param bean the bean to store or update
     */
    void save(String uid, Object bean) throws BeanStoreException;
    
    /**
     * Load all the bean of a certain type
     * @param <T> the bean type
     * @param beanClass the class of the bean
     * @return a list of the loaded beans
     * @throws BeanStoreException if loading fails
     */
    <T> ListExt<T> loadAll(Class<T> beanClass) throws BeanStoreException;

    /**
     * Load the bean with the given uid
     * @param uid the uid of the bean to load
     * @return the bean at the given uid
     */
    OptionalValue<Object> load(String uid) throws BeanStoreException;

    /**
     * Load the bean with the given uid and type
     * @param <T> the type of the bean to load
     * @param uid the uid of the bean
     * @param beanClass the type of the bean
     * @return the loaded bean
     */
    <T> OptionalValue<T> load(String uid, Class<T> beanClass) throws BeanStoreException;

    /**
     * Save or update a bean, using the fully qualified class name of its type
     * as the uid
     * @param bean the bean to store
     */
    void save(Object bean) throws BeanStoreException;

    /**
     * Load the bean of the given type stored with the fully qualified name of
     * bean class as uid
     * @param <T> the type of the bean
     * @param beanClass the type of the bean
     * @return the loaded bean
     */
    <T> OptionalValue<T> load(Class<T> beanClass) throws BeanStoreException;

    /**
     * Generates a unique identifier
     * @return a new unique identifier
     */
    String generateUid();

    /**
     * Executes a function on all the beans in this store until the function
     * returns false
     * @param op the function to execute. Execution stops when the function
     * returns false.
     */
    void foreach(Function1<Object, Boolean> op);

    /**
     * Opens a stream to write a binary output in the store
     * @param uid the binary output uid
     * @return the binary output
     * @throws IOException if open fails
     */
    BufferedOutputStream openBinaryOutput(String uid) throws IOException;

    /**
     * Opens a stream to read a binary input from the store
     * @param uid the binary input uid
     * @return the binary input or null
     * @throws IOException if open fails
     */
    BufferedInputStream openBinaryInput(String uid) throws IOException;
    
    /**
     * Opens a stream to write binary data in the store
     * @param <T> the type of the value returned by the output stream call
     * @param uid the uid of the binary output
     * @param call the stream process
     * @return the value returned by the stream call
     */
    <T> T withBinaryOutput(String uid, OutputStreamCall<T> call);
    
    /**
     * Opens a stream to read binary data from the store
     * @param <T> the type of the value returned by the input stream call
     * @param uid the uid of the binary input
     * @param call the stream process
     * @return  the value returned by the stream call
     */
    <T> T withBinaryInput(String uid, InputStreamCall<T> call);

    /**
     * Stores an array of bytes as a binary entry in this bean store
     * @param uid the uid of the binary file
     * @param bytes the data of the file
     */
    void saveBinary(String uid, byte[] bytes);

    /** Find all the beans whose file contains one of the raw words listed. For each bean call function1. Stops when function returns false*/
    public void foreach(String[] keywords, Function1<Object, Boolean> function1);

    public void dumpDebug();
    
    void backup();
}